// PackageRenameTransform.groovy
package com.kasax.plugin.shadow

import com.android.build.api.transform.*
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.internal.pipeline.TransformManager
import com.kasax.plugin.shadow.utils.LogUtils
import org.apache.commons.io.FileUtils
import org.gradle.api.Project
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.commons.ClassRemapper

import java.util.jar.JarEntry
import java.util.jar.JarFile
import java.util.jar.JarOutputStream

public class PackageRenameTransform extends Transform {
    private static final String LOG_TAG = "PackageRenameTransform"
    private final Project project
    private final RenamePackageExtension extension
    private final BaseExtension android
    private final Set<String> processedJars = [] as Set

    PackageRenameTransform(Project project, RenamePackageExtension extension, BaseVariant variant) {
        this.project = project
        this.extension = extension
        this.android = project.extensions.getByType(BaseExtension)
    }

    @Override
    String getName() { "PackageRenameTransform" }

    @Override
    Set<QualifiedContent.ContentType> getInputTypes() { TransformManager.CONTENT_CLASS }

    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        // 覆盖本工程产物 + 依赖（库模块不要用 PROJECT_ONLY，否则只有依赖没有本工程产物）
        TransformManager.SCOPE_FULL_PROJECT
    }

    @Override
    boolean isIncremental() { false } // 先用非增量，稳定后再考虑增量

    @Override
    void transform(TransformInvocation invocation) throws TransformException, InterruptedException, IOException {
        super.transform(invocation)
        LogUtils.d(LOG_TAG, "transform exec")
//        def inputs = invocation.inputs
//        def outputProvider = invocation.outputProvider
//        def variantName = variant.name.capitalize()
//        LogUtils.d(LOG_TAG, "Transform started for variant: ${variantName}")
//        LogUtils.d(LOG_TAG, "Input types: ${getInputTypes()}")
//        LogUtils.d(LOG_TAG, "Scopes: ${getScopes()}")
//        LogUtils.d(LOG_TAG, "Inputs count: ${inputs.size()}")
//
//        inputs.each { TransformInput input ->
//            // 1) 处理目录输入：优先处理本工程 javac 产物目录（intermediates/javac/.../classes）
//            input.directoryInputs.each { dirInput ->
//                def dir = dirInput.file
//                if (dir.exists()) {
//                    // 只处理真正的 classes 目录（名称不一定是 "classes"，AGP 4.x 可能带变体后缀）
//                    if (dir.name.endsWith('/classes') || dir.name.endsWith("-classes")) {
//                        def rel = project.file('src/main/java').toPath().relativize(dir.toPath().parent)
//                        def scopePath = variantName
//                        if (rel) scopePath = "${scopePath}/${rel.toString().replace(File.separator, '/')}"
//                        def destDir = outputProvider.getContentLocation(scopePath, input.contentTypes, input.scopes, Format.DIRECTORY)
//                        LogUtils.d(LOG_TAG, "Processing directory input: ${dir}")
//                        processDirectory(dir, destDir)
//                        LogUtils.d(LOG_TAG, "Directory processed: ${dir}")
//                    }
//                }
//            }
//
//            // 2) 处理 jar 输入：避免重复处理与循环
//            input.jarInputs.each { jarInput ->
//                def file = jarInput.file
//                def name = file.name
//                if (!name.endsWith('.jar')) return
//
//                def digest = org.apache.commons.codec.digest.DigestUtils.md5Hex(file.canonicalPath)
//                def key = "${name}_${digest}"
//                if (processedJars.contains(key)) return
//                processedJars.add(key)
//                LogUtils.d(LOG_TAG, "Processing jar input: ${file}")
//                def dest = outputProvider.getContentLocation(name, input.contentTypes, input.scopes, Format.JAR)
//                handleProcessJar(file, dest)
//                LogUtils.d(LOG_TAG, "Jar processed: ${file}")
//            }
//        }
    }

    private void processDirectory(File dir, File dest) {
        if (!dir.exists()) return
        FileUtils.forceMkdir(dest)
        LogUtils.d(LOG_TAG, "Processing directory: ${dir}")
        dir.eachFileRecurse { f ->
            if (!f.isFile() || !f.name.endsWith('.class')) return
            def rel = dir.toPath().relativize(f.toPath())
            def target = new File(dest, rel.toString())
            FileUtils.forceMkdirParent(target)
            LogUtils.d(LOG_TAG, "Processing class file: ${f}")
            byte[] bytes = f.bytes
            byte[] rewritten = rewriteClass(bytes)
            if (rewritten != null) {
                f.withOutputStream { it.write(rewritten) } // 原地改写输入目录，确保后续任务读到新内容
                LogUtils.d(LOG_TAG, "Class file rewritten: ${f}")
            }
        }
    }

    private void handleProcessJar(File sourceJar, File targetFile) {
        def tmp = File.createTempFile('sourceJar-rename-', '.sourceJar')
        tmp.deleteOnExit()
        LogUtils.d(LOG_TAG, "Processing sourceJar file: ${sourceJar}")
        new JarOutputStream(new FileOutputStream(tmp)).withCloseable { jos ->
            new JarFile(sourceJar).withCloseable { jf ->
                jf.entries().each { Ze ->
                    if (Ze.name == 'META-INF/MANIFEST.MF') {
                        jos.putNextEntry(new JarEntry(Ze.name))
                        jos << jf.getInputStream(Ze)
                        jos.closeEntry()
                        return
                    }
                    if (!Ze.name.endsWith('.class')) {
                        jos.putNextEntry(new JarEntry(Ze.name))
                        jos << jf.getInputStream(Ze)
                        jos.closeEntry()
                        return
                    }
                    LogUtils.d(LOG_TAG, "Processing class entry in sourceJar: ${Ze.name}")
                    def bytes = jf.getInputStream(Ze).bytes
                    def rewritten = rewriteClass(bytes)
                    if (rewritten != null) {
                        jos.putNextEntry(new JarEntry(Ze.name))
                        jos << rewritten
                        jos.closeEntry()
                        LogUtils.d(LOG_TAG, "Class entry rewritten in sourceJar: ${Ze.name}")
                    }
                }
            }
            FileUtils.moveFile(tmp, targetFile)
        }
    }

    private byte[] rewriteClass(byte[] bytes) {
        def cr = new ClassReader(bytes)
        def cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS)
        def remapper = new PackageRemapper(extension.packageMapping)
        def visitor = new ClassRemapper(cw, remapper)
        try {
            cr.accept(visitor, ClassReader.EXPAND_FRAMES)
            return cw.toByteArray()
        } catch (Throwable t) {
            project.logger.warn("跳过类重写: ${cr.className}, 原因: ${t.message}")
            return null
        }
    }
}